package com.idata.service.services;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson2.JSONObject;
import com.idata.model.dto.KGProxySearchResultDTO;
import com.idata.model.entity.DisputeEntity;
import com.idata.model.enums.AssociationTypeEnum;
import com.idata.model.enums.DisputeSourceEnum;
import com.idata.model.enums.StatisticsTypeForInputEnum;
import com.idata.model.interfaces.HasHotWordContext;
import com.idata.model.proxyDO.KGCitizenDO;
import com.idata.model.proxyDO.KGDisputeInfoForRelationDO;
import com.idata.model.proxyDO.KGDisputeInfoForRelationDO.KGDisputeInfoDO;
import com.idata.model.proxyDO.KGDisputeInfoForRelationDO.UserInfoDO;
import com.idata.model.proxyDO.KGResponseDO;
import com.idata.model.request.CaseIdListRequest;
import com.idata.model.request.IdCardRequest;
import com.idata.model.request.StatisticsRequest;
import com.idata.model.response.CitizenResponse;
import com.idata.model.response.CitizenSearchResponse;
import com.idata.model.response.DisputeRelationResponse;
import com.idata.model.response.DisputeStatisticsResponse;
import com.idata.model.response.DisputeWordResponse;
import com.idata.model.response.GraphStatisticsResponse;
import com.idata.model.response.PageResult;
import com.idata.model.response.PhoneInfoResponse;
import com.idata.model.response.TagResponse;
import com.idata.service.config.ProxyUrlProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PortaitAnalysisService {

    @Autowired
    private CitizenInfoService citizenInfoService;

    @Autowired
    private DisputeService disputeService;

    @Autowired
    private ProxyUrlProperties proxyUrlProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AssociationQueryManager associationQueryManager;

    @Autowired
    @Qualifier("disputeHotWordServiceWebImpl")
    private DisputeHotWordService disputeHotWordService;

    public CitizenSearchResponse getBaseInfo(String idCard) {
        CitizenSearchResponse response = new CitizenSearchResponse();
        PageResult<KGProxySearchResultDTO> kgPageResponse = citizenInfoService.proxySearchCitizen(idCard, 0, 5);
        if (!kgPageResponse.getTotal().equals(1L) || CollectionUtils.isEmpty(kgPageResponse.getList()) || kgPageResponse.getList().size() != 1) {
            log.error("The returned result does not meet the requirements, the idCard is {}", idCard);
        }
        List<KGProxySearchResultDTO> kgProxySearchResultDTOS = kgPageResponse.getList();
        if (!CollectionUtils.isEmpty(kgProxySearchResultDTOS)) {
            KGCitizenDO kgCitizenDO = kgProxySearchResultDTOS.get(0).getKgCitizenDO();
            response.setCitizenInfo(CitizenResponse.convertFromKGCitizen(kgCitizenDO));
            Map<String, List<TagResponse>> tagMap = associationQueryManager.getTagMap(ListUtil.toList(kgProxySearchResultDTOS.get(0)));
            response.setTagList(tagMap.get(kgCitizenDO.getPeople().getIdCard()));
        }

        List<PhoneInfoResponse> phones = citizenInfoService.proxyGetPhoneMap(ListUtil.toList(idCard)).get(idCard);
        response.setPhoneList(phones);

        List<DisputeWordResponse> hotWords = new ArrayList<>();
        try {
            hotWords = this.getDisputeWordList(idCard);
        } catch (Exception e) {
            log.error("调用纠纷热词接口报错", e);
        }
        response.setDisputeWordList(hotWords);
        initResponse(idCard, response);
        return response;
    }

    // todo delete
    private void initResponse(String idCard, CitizenSearchResponse response) {
        IdCardRequest request = new IdCardRequest(idCard);
        DisputeStatisticsResponse disputeStatistics = this.getDisputeStatistics(request);
        BeanUtils.copyProperties(disputeStatistics, response);
    }

    public List<DisputeWordResponse> getDisputeWordList(String idCard) {
        DisputeEntity disputeEntity = disputeService.getGraphAtlas(idCard);
        List<Object> disputeInfoList = disputeService.obtainDisputeInfoList(disputeEntity.getDisputeIdList());
        List<String> hotWordList = new ArrayList<>();
        for (Object disputeInfo : disputeInfoList) {
            if (!(disputeInfo instanceof HasHotWordContext)) {
                continue;
            }
            hotWordList.addAll(((HasHotWordContext) disputeInfo).getHotWordContext());
        }
        String hotWordContext = hotWordList.stream().filter(Objects::nonNull).collect(Collectors.joining("####"));
        List<DisputeWordResponse> hotWords = disputeHotWordService.getHotWords(hotWordContext);
        return hotWords;
    }

    /**
     * 获取纠纷实体和纠纷关系
     */
    public GraphStatisticsResponse getGraphStatistics(StatisticsRequest statisticsRequest) {
        String idCard = statisticsRequest.getIdCard();
        Integer statisticsType = statisticsRequest.getStatisticsType();
        StatisticsTypeForInputEnum statisticsEnum = StatisticsTypeForInputEnum.of(statisticsType);
        GraphStatisticsResponse response = new GraphStatisticsResponse();
        // 根据id 获取 纠纷列表
        List<String> disputeIds = disputeService.obtainDisputeRelatedType(idCard, AssociationTypeEnum.ALL, statisticsEnum);
        log.info("obtainDisputeRelatedType called result is {}", disputeIds);
        Map<String, Integer> entityCounter = this.getEntityStats(disputeIds);
        response.setEntity(entityCounter);

        Map<String, Integer> relationCounter = this.getDisputeRelationStats(idCard, disputeIds);
        response.setRelation(relationCounter);
        return response;
    }

    private Map<String, Integer> getEntityStats(List<String> disputeIds) {
        Map<String, Integer> entityCounter = new HashMap<>();
        List<String> allEntity = new ArrayList<>();

        Map<String, List<String>> disputeEntityStatistics = proxyDisputeEntityStatistics(disputeIds);
        for (Entry<String, List<String>> entry : disputeEntityStatistics.entrySet()) {
            allEntity.addAll(entry.getValue().stream().filter(Objects::nonNull).collect(Collectors.toList()));
        }
        for (String entity : allEntity) {
            entityCounter.put(entity, entityCounter.getOrDefault(entity, 0) + 1);
        }
        return entityCounter;
    }

    /**
     * 纠纷实体统计
     */
    public Map<String, List<String>> proxyDisputeEntityStatistics(List<String> disputeIds) {
        String url = this.proxyUrlProperties.getProxyUrl().getKg() +
               "/maotiao_backend/search/getDisputeEntityStatistics";
        HttpEntity<CaseIdListRequest> requestParam = new HttpEntity<>(new CaseIdListRequest().setCaseIdList(disputeIds));
        ParameterizedTypeReference<KGResponseDO<Map<String, List<String>>>> typeReference = new ParameterizedTypeReference<KGResponseDO<Map<String, List<String>>>>() {};
        ResponseEntity<KGResponseDO<Map<String, List<String>>>> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestParam, typeReference);
        return responseEntity.getBody().getData();
    }



    public Map<String, List<DisputeRelationResponse>> getDisputeRelation(List<String> srcIdCardList, Integer statisticsType) {
        StatisticsTypeForInputEnum statisticsEnum = StatisticsTypeForInputEnum.of(statisticsType);

        // 获取 srcIdCardList 和 哪些人发生了纠纷，纠纷信息又是什么
        Map<String, Map<String, KGDisputeInfoForRelationDO>> disputeRelationMap = citizenInfoService.proxyGetDisputeRelationMap(srcIdCardList);
        HashMap<String, List<DisputeRelationResponse>> resultMap = new HashMap<>();
        for (Map.Entry<String, Map<String, KGDisputeInfoForRelationDO>> disputeRelationMapForOneCivilizen : disputeRelationMap.entrySet()) {
            List<DisputeRelationResponse> resultForSrcIdCard = new ArrayList<>();
            // srcIdCard : 被查询人
            String srcIdCard = disputeRelationMapForOneCivilizen.getKey();
            // todo 确认是否应该对srcIdCard进行调用，以及是否应该在这调用
            List<String> disputeIds = disputeService.obtainDisputeRelatedType(srcIdCard, AssociationTypeEnum.ALL, statisticsEnum);
            log.info("obtainDisputeRelatedType called result is {}", disputeIds);
            // disputeRelationForSrcIdCard 被查询人的另一纠纷方
            Map<String, KGDisputeInfoForRelationDO> disputeRelationForSrcIdCard = disputeRelationMapForOneCivilizen.getValue();
            List<String> dstIdCardList = new ArrayList<>(disputeRelationForSrcIdCard.keySet());
            // 纠纷总数
            Map<String, Long> dstDisputeTotalMap = getDisputeTotal(dstIdCardList);
            // 查询纠纷关系。根据被查id和theOtherIDNo之间查找纠纷关系
            Map<String, List<String>> dstRelationMap = citizenInfoService.proxyGetRelationTagMap(srcIdCard, dstIdCardList);
            // key是 name+idNo，value是纠纷列表
            for (Map.Entry<String, KGDisputeInfoForRelationDO> entry : disputeRelationForSrcIdCard.entrySet()) {
                String dstIdCard = entry.getKey();
                // 获取两者之间发生的所有纠纷列表
                List<String> disputeListBetweenTwoCivilizen = entry.getValue().getCaseList().stream().map(KGDisputeInfoDO::getDisputeId).distinct().collect(Collectors.toList());
                // 根据 纠纷id 做过滤 比如 警情，案件 等，以此判断纠纷另一方是否作为结果返回
                Collection<String> intersectionDisputeIdList = CollectionUtil.intersection(disputeIds, disputeListBetweenTwoCivilizen);
                if (CollectionUtil.isNotEmpty(intersectionDisputeIdList)) {
                    resultForSrcIdCard.add(new DisputeRelationResponse()
                            .setRelationshipList(dstRelationMap.get(dstIdCard))
                            .setName(Optional.ofNullable(entry.getValue()).map(KGDisputeInfoForRelationDO::getUserInfo).map(UserInfoDO::getUserName).orElse(""))
                            .setIdCard(dstIdCard)
                            .setDisputeTotalCount(dstDisputeTotalMap.getOrDefault(dstIdCard, 0L))
                            .setPersonDisputeCount(disputeListBetweenTwoCivilizen.size())
                            .setAvatarUrl(Optional.ofNullable(entry.getValue()).map(KGDisputeInfoForRelationDO::getUserInfo).map(UserInfoDO::getAvatarUrl).orElse(""))
                    );
                }
            }
            if (CollectionUtil.isNotEmpty(resultForSrcIdCard)) {
                List<DisputeRelationResponse> disputeRelationResponseList =
                        resultForSrcIdCard.stream()
                                .sorted(Comparator.comparingLong(DisputeRelationResponse::getDisputeTotalCount).reversed())
                                .collect(Collectors.toList());
                resultMap.put(srcIdCard, disputeRelationResponseList);
            }
        }

        return resultMap;
    }

    public Map<String, Integer> getDisputeRelationStats(String idCard, List<String> disputeIds) {
        // 1、先获取与被检索人张三有纠纷的人，如李四的用户信息和纠纷列表
        Map<String, KGDisputeInfoForRelationDO> disputeRelationMap = citizenInfoService.proxyGetDisputeRelationMap(ListUtil.toList(idCard)).get(idCard);
        if (CollectionUtils.isEmpty(disputeRelationMap)) {
            return new HashMap<>();
        }
        // 2、将张三与李四的纠纷列表和传入的纠纷id作交，判断李四是否满足条件，满足则进行下一步
        Map<String, Collection<String>> idCardAndDisputeIdMap = disputeRelationMap.entrySet().stream()
                .collect(Collectors.toMap(Entry::getKey,
                        entry -> CollectionUtil.intersection(entry.getValue().getCaseList().stream().map(KGDisputeInfoDO::getDisputeId).collect(Collectors.toList()), disputeIds),
                        (oldValue, newValue) -> newValue));
        // 获得 idCard 和 其他人的纠纷id，其中 idCardAndDisputeIdMap 的key是纠纷人id，value是其他人的纠纷id列表
        idCardAndDisputeIdMap = idCardAndDisputeIdMap.entrySet().stream().filter(entry-> CollectionUtil.isNotEmpty(entry.getValue())).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
        // 3、再获取 张三 和 李四类人 的关系
        Map<String, List<String>> idAndRelationMap = citizenInfoService.proxyGetRelationTagMap(idCard, new ArrayList<>(idCardAndDisputeIdMap.keySet()));
        log.info("getDisputeRelationStats called, idAndRelationMap is {}", JSONObject.toJSONString(idAndRelationMap));
        // 4、对张三和李四类人的关系进行统计，每出现一种关系，counter+1
        // key: relationName, value: List<IdCard>
        Map<String, Set<String>> counter = new HashMap<>();
        for (Entry<String, List<String>> idAndRelation : idAndRelationMap.entrySet()) {
            for (String relation : idAndRelation.getValue()) {
                Set<String> counterDisputeIdListInMap = counter.getOrDefault(relation, new HashSet<>());
                counterDisputeIdListInMap.add(idAndRelation.getKey());
                counter.put(relation, counterDisputeIdListInMap);
            }
        }
        Map<String, Integer> result = counter.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().size()));
        return result;
    }

    private Map<String, Long> getDisputeTotal(List<String> idCardList) {
        Map<String, Map<String, KGDisputeInfoForRelationDO>> disputeRelationMap = citizenInfoService.proxyGetDisputeRelationMap(idCardList);
        return disputeRelationMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
                entry->entry.getValue().values().stream().map(KGDisputeInfoForRelationDO::getCaseList).flatMap(List::stream).map(KGDisputeInfoDO::getDisputeId).distinct().count(),
                (oldValue,newValue) -> newValue));
    }

    public DisputeStatisticsResponse getDisputeStatistics(IdCardRequest idCardRequest) {
        DisputeEntity disputeEntity = disputeService.getGraphAtlas(idCardRequest.getIdCard());
        return new DisputeStatisticsResponse()
                .setDisputeTotalCount(disputeEntity.getDisputeIdList().size())
                .setCollaborativeCaseCount(disputeEntity.getDisputeSourceMap().getOrDefault(DisputeSourceEnum.COLLABORATIVE_CASE.getCode(), new ArrayList<>()).size())
                .setPolice110Count(disputeEntity.getDisputeSourceMap().getOrDefault(DisputeSourceEnum.POLICE_110.getCode(), new ArrayList<>()).size())
                .setHighRiskCount(disputeEntity.getDisputeSourceMap().getOrDefault(DisputeSourceEnum.HIGH_RISK.getCode(), new ArrayList<>()).size())
                ;
    }

    public List<Object> getDisputeHistory(StatisticsRequest statisticsRequest) {
        StatisticsTypeForInputEnum statisticsEnum = StatisticsTypeForInputEnum.of(statisticsRequest.getStatisticsType());
        AssociationTypeEnum associationEnum = AssociationTypeEnum.fromCode(statisticsRequest.getAssociationType());
        List<String> disputeIds = disputeService.obtainDisputeRelatedType(statisticsRequest.getIdCard(), associationEnum, statisticsEnum);
        log.info("obtainDisputeRelatedType called result is {}", disputeIds);
        List<Object> response = disputeService.obtainDisputeInfoList(disputeIds);
        return response;
    }
}
